#ifndef ACTIONTRACK_H
#define ACTIONTRACK_H

#include <QObject>

class RobotAction;

//Due to the fact that multiple inheritance is not supported for QObjects,
//we cannot enforce ActionTrackSignals and ActionTrackSlots to define interfaces
//for signals and slots, they can only be declared as virtual functions.
//Here is the documentation of the patterns that have to be used:
//   http://doc.trolltech.com/qq/qq15-academic.html#multipleinheritance
class RobotActionTrack;

/**
 * @brief Defines the signals that are inherited by subclasses of
 * ActionTrack.
 *
 * They cannot be defined as signals by the interface because
 * multiple inheritance is not supported for QObjects.  Please
 * see http://doc.trolltech.com/qq/qq15-academic.html#multipleinheritance
 * for an explaination of the patterns that are being used
 *
 */
class RobotActionTrackSignals{
public:
    /**
     * @brief Signal emitted whenever an item in the action track (such
     * as a key frame or sound) is created.
     *
     * @param timestamp The timestamp (in milliseconds) of the item created.
     */
    virtual void itemCreated(int timestamp) = 0;
    /**
     * @brief Signal emitted whenever an item in the action track is deleted.
     *
     * @param timestamp The timestamp (in milliseconds) of the item before
     * it was deleted.
     */
    virtual void itemDeleted(int timestamp) = 0;
    /**
     * @brief Signal emitted whenever an item in the action track is moved.
     *
     * @param newTimestamp The new timestamp, in milliseconds, of the item.
     * @param oldTimestamp The timestamp, in milliseconds, of the item before it was moved.
     */
    virtual void itemMoved(int newTimestamp, int oldTimestamp) = 0;
};


/**
 * @brief The wrapper contained by the ActionTrack subclasses, through
 * which signals and slots are defined and interacted.
 *
 * Subclasses of ActionTrack contain a wrapper that inherits QObject
 * so that it can define an interface for signals and slots.  Thus,
 * composition is used instead of inheritance to overcome the problem
 * of multiple inheritance with QObjects.  The only trick is that
 * ActionTrack subclasses have to cast to this class's signals in
 * order to send them.  See
 * http://doc.trolltech.com/qq/qq15-academic.html#multipleinheritance
 * for more detail about the pattern that is being used.
 *
 */
class RobotActionTrackWrapper : public QObject, public RobotActionTrackSignals{
    Q_OBJECT

private:
    RobotActionTrack* _wrappedObject;

public:
    RobotActionTrackWrapper(RobotActionTrack* parent): _wrappedObject(parent){}

signals:
    void itemCreated(int timestamp);
    void itemDeleted(int timestamp);
    void itemMoved(int newTimestamp, int oldTimestamp);
};


/**
 * @brief Defines a base for all subclasses of editable "tracks" in
 * the RobotAction.
 *
 * It allows us to define an interface for signals and slots that
 * indicate when an "item", whether that be a sound, key frame, or
 * something else, is changed in the RobotAction.  For example, the
 * GUITimelineTrack class can listen to its associated track and
 * update the GUI when an item is created, deleted, or moved.  The whole
 * point of these classes is to use good inheritance to eliminate
 * code duplication and provide more flexibility down the road.
 *
 * Each ActionTrack subclass is given a wrapper that defines the interfaces
 * for signals and slots.  Those classes wishing to connect to the signals
 * and slots must call actionTrackWrapper() to obtain the wrapper and
 * connect to it.  In order for signals to be called appropriately from
 * the wrapper, subclasses of ActionTrack must cast the call to
 * the ActionTrackWrapper class.  Please see
 * http://doc.trolltech.com/qq/qq15-academic.html#multipleinheritance
 * for an explanation of the design pattern.
 *
 */
class RobotActionTrack{
protected:
    RobotActionTrackWrapper* _wrapper;

public:
    RobotActionTrack(): _wrapper(new RobotActionTrackWrapper(this)){}
    RobotActionTrackWrapper* trackWrapper(){return _wrapper;}
};


#endif // ACTIONTRACK_H
